package com.easondongh.system.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import com.easondongh.system.common.ActiveUser;
import com.easondongh.system.domain.SysUser;
import com.easondongh.common.enums.ResponseEnum;
import com.easondongh.common.response.ResponseObj;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author EasonDongH
 * @date 2020/4/28 16:19
 */
@Slf4j
@Controller
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 登录成功返回TOKEN
     * @param sysUser
     * @return
     */
    @PostMapping(value = "/doLogin")
    @ResponseBody
    public ResponseObj<Object> doLogin(@RequestBody SysUser sysUser) {
        if(sysUser == null || StringUtils.isBlank(sysUser.getLoginName()) || StringUtils.isBlank(sysUser.getPassword())) {
            log.warn("登录用户名或密码不能为空");
            return new ResponseObj<>(ResponseEnum.INVALID_USERNAME_OR_PASSWORD);
        }
        String keyCode = sysUser.getKeyCode();
        String captcha = sysUser.getCaptcha();
        if(StringUtils.isBlank(keyCode) || StringUtils.isBlank(captcha)) {
            log.warn("登录时keyCode、验证码不能为空：keyCode={}，captcha={}",keyCode,captcha);
            return new ResponseObj<>(ResponseEnum.INVALID_CAPTCHA);
        }
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String actualCode = opsForValue.get(keyCode);
        if(StringUtils.isBlank(actualCode)) {
            return new ResponseObj<>(ResponseEnum.CAPTCHA_EXPIRED);
        }
        if(!actualCode.equalsIgnoreCase(captcha)) {
            return new ResponseObj<>(ResponseEnum.CAPTCHA_ERROR);
        }

        try {
            Subject subject = SecurityUtils.getSubject();
            AuthenticationToken authenticationToken = new UsernamePasswordToken(sysUser.getLoginName(), sysUser.getPassword());
            subject.login(authenticationToken);
            Serializable sessionId = subject.getSession().getId();
            Map<String,Object> returnMap = new HashMap<>(2);
            returnMap.put("token", sessionId);
            ActiveUser activeUser= (ActiveUser) subject.getPrincipal();
            returnMap.put("permissions", activeUser.getPermissions());
            returnMap.put("usertype", activeUser.getUser().getType());
            returnMap.put("username", activeUser.getUser().getName());
            return new ResponseObj<>(ResponseEnum.LOGIN_SUCCESS, returnMap);
        } catch (Exception ex) {
            log.error("登录失败：loginName={}; pwd=", sysUser.getLoginName(), sysUser.getPassword(), ex);
            return new ResponseObj<>(ResponseEnum.INVALID_USERNAME_OR_PASSWORD);
        }
    }

    /**
     * 实时检测当前用户是否还在登录状态（登录过期、登录TOKEN被清除）
     * @return
     */
    @GetMapping("/checkLogin")
    @ResponseBody
    public ResponseObj<Boolean> checkLogin() {
        Subject subject = SecurityUtils.getSubject();
        boolean hasLogin = subject.isAuthenticated();
        return new ResponseObj<>(ResponseEnum.QUERY_SUCCESS, hasLogin);
    }

    /**
     * 验证码
     */
    @GetMapping("/captcha")
    public void captcha(HttpServletResponse response, String keyCode) throws IOException {
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(100, 38, 4, 2);
        String code = captcha.getCode();
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        opsForValue.set(keyCode, code);
        opsForValue.getOperations().expire(keyCode,60, TimeUnit.SECONDS);
        captcha.write(response.getOutputStream());
    }
}
